package com.qd.extcam;

import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Method;
import java.util.Calendar;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.ChannelListener;
import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.qd.wifidirect.WiFiDirectBroadcastReceiver;

public class MainActivity extends Activity implements ChannelListener, ConnectionInfoListener {
	 public static final String TAG = "ExtCamMainActivity";
	 private SurfaceHolder holder;
	 private SurfaceView cameraView;
	 private Context context;
	 private ExtRecorder er;
	
	 private boolean mIsStart = false;
	 private SensorManager mSensorManager;
	 private int mSensorDelay = SensorManager.SENSOR_DELAY_NORMAL;	// SENSOR_DELAY_FASTEST > SENSOR_DELAY_GAME > SENSOR_DELAY_UI > SENSOR_DELAY_NORMAL
	 private LogFile mSensorLogFile = null;
	 private long mSensorCount = 0;

	 // GPS variable
	 private LocationManager mLocationManager;
	 private long mLocationTime = 0;			// milliseconds
	 private float mLocationDistance = 0;	// meters
	 private LogFile mLocationLogFile = null;
	 private long mLocationCount = 0;
	 
	 // WifiDirect
	 private WifiP2pManager manager;
     private boolean isWifiP2pEnabled = false;
     private boolean retryChannel = false;

     private final IntentFilter intentFilter = new IntentFilter();
     private Channel channel;
     private BroadcastReceiver receiver = null;
	 
     public void setIsWifiP2pEnabled(boolean isWifiP2pEnabled) {
         this.isWifiP2pEnabled = isWifiP2pEnabled;
     }
   
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	
		cameraView = (SurfaceView)findViewById(R.id.smallcameraview);
        context = this.getApplicationContext();
        
        //wifidirect
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);

        manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
        channel = manager.initialize(context, getMainLooper(), null);
        
        try {
            Class<?> wifiManager = Class
                    .forName("android.net.wifi.p2p.WifiP2pManager");

            Method method = wifiManager
                    .getMethod(
                            "enableP2p",
                            new Class[] { android.net.wifi.p2p.WifiP2pManager.Channel.class });

            method.invoke(manager, channel);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        // Sensor & GPS
		mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
		mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

		// Sensor & GPS Log File
		mSensorLogFile = new LogFile(this);
		mSensorLogFile.setFileName("log_sensor.txt");
		mLocationLogFile = new LogFile(this);
		mLocationLogFile.setFileName("log_gps.txt");
	
            
        Button bt = (Button)findViewById(R.id.start_button);
        bt.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				// Determines if user is connected to a wireless network & displays ip
				startRecording();
			}
        });
             
        bt = (Button)findViewById(R.id.stop_button);
        bt.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				stopRecording();
				finish();
			}
        });
		
	}

	public void startRecording(){
		if(er == null){
			er = new ExtRecorder(cameraView.getHolder());
			er.setSensorFile(mSensorLogFile.getFileNameWithFullPath());
			er.InitMediaRecorder();
			er.prepare();
			er.start();
		}
		
		registerSensorListener(mSensorDelay);
		//mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, mLocationTime, mLocationDistance, mLocationListener);
	}
	
	public void stopRecording() {
		mSensorManager.unregisterListener(mSensorListener);
		//mLocationManager.removeUpdates(mLocationListener);
		if(er != null)
			er.stop();
		er = null;
	}
	@Override
	public void onDestroy() {
		super.onDestroy();
	}
	
	@Override
    public void onResume() {
        super.onResume();
        receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
        registerReceiver(receiver, intentFilter);
    }

    @Override
    public void onPause() {
        super.onPause();
        unregisterReceiver(receiver);
    }
    
	private void registerSensorListener(int delay) {
		mSensorManager.unregisterListener(mSensorListener);
		mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), delay);
		mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), delay);
		mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), delay);
	}

	SensorEventListener mSensorListener = new SensorEventListener() {
		private float[] mAccelerometerData, mMagneticData;
		private float[] mRotation = new float[9];
		private float[] mResult = new float[3];	// azimuth, pitch, roll
		private float mAzimuth;	// 방위각
		private float mPitch;	// 상하 기울기
		private float mRoll;	// 좌우 기울기

		public void onAccuracyChanged(Sensor sensor, int accuracy) {
			Log.d(TAG, "onAccuracyChanged(" + accuracy + ")");
		}

		public void onSensorChanged(SensorEvent event) {
			switch (event.sensor.getType()) {
			case Sensor.TYPE_ACCELEROMETER:
				mAccelerometerData = event.values.clone();
				break;
			case Sensor.TYPE_MAGNETIC_FIELD:
				mMagneticData = event.values.clone();
				return;
			case Sensor.TYPE_GYROSCOPE:
			default:
				return;
			}

			if ((null != mAccelerometerData) && (null != mMagneticData)) {
				SensorManager.getRotationMatrix(mRotation, null, mAccelerometerData, mMagneticData);
				SensorManager.getOrientation(mRotation, mResult);

				mAzimuth = (float)Math.toDegrees(mResult[0]);
				if (0 > mAzimuth) {
					mAzimuth += 360;
				}
				mPitch = (float)Math.toDegrees(mResult[1]);
				mRoll = (float)Math.toDegrees(mResult[2]);

				
				String log = mAzimuth + ", " + mPitch + ", " + mRoll;
				mSensorLogFile.write(log);
				

				mSensorCount++;
				TextView tv = (TextView)findViewById(R.id.msg_textview);
				tv.setText(String.format("S:%d/A:%f/P:%f/R:%f", mSensorCount, mAzimuth, mPitch, mRoll));
				/*((TextView)findViewById(R.id.tv_sensor)).setText("Sensor : " + mSensorCount);
				((TextView)findViewById(R.id.tv_azimuth)).setText("Azimuth : " + mAzimuth);
				((TextView)findViewById(R.id.tv_pitch)).setText("Pitch : " + mPitch);
				((TextView)findViewById(R.id.tv_roll)).setText("Roll : " + mRoll);*/
			}
		}
	};

	LocationListener mLocationListener = new LocationListener() {
		private double mLatitude;	// 위도
		private double mLongitude;	// 경도
		private float mSpeed;		// 속도

		public void onLocationChanged(Location location) {
			double latitude = location.getLatitude();
			double longitude = location.getLongitude();
			float speed = (float)(location.getSpeed() * 3.6);	// m/s -> m/h

			if ((mLatitude != latitude) || (mLongitude != longitude) || (mSpeed != speed)) {
				mLatitude = latitude;
				mLongitude = longitude;
				mSpeed = speed;

				
				String log = mLatitude + ", " + mLongitude + ", " + mSpeed;
				mLocationLogFile.write(log);
				

				mLocationCount++;
				/*((TextView)findViewById(R.id.tv_gps)).setText("Gps : " + mLocationCount);
				((TextView)findViewById(R.id.tv_latitude)).setText("Latitude : " +mLatitude);
				((TextView)findViewById(R.id.tv_longitude)).setText("Longitude : " + mLongitude);
				((TextView)findViewById(R.id.tv_speed)).setText("Speed : " + mSpeed);*/
			}
		}

		public void onProviderDisabled(String provider) {
			Log.d(TAG, "onProviderDisabled(" + provider + ")");
		}

		public void onProviderEnabled(String provider) {
			Log.d(TAG, "onProviderEnabled(" + provider + ")");
		}

		public void onStatusChanged(String provider, int status, Bundle extras) {
			Log.d(TAG, "onStatusChanged(" + provider + ", " + status + ")");
		}
	};

	 

    @Override
    public void onChannelDisconnected() {
        // we will try once more
        if (manager != null && !retryChannel) {
            Toast.makeText(this, "Channel lost. Trying again", Toast.LENGTH_LONG).show();
            retryChannel = true;
            manager.initialize(this, getMainLooper(), this);
        } else {
            Toast.makeText(this,
                    "Severe! Channel is probably lost premanently. Try Disable/Re-Enable P2P.",
                    Toast.LENGTH_LONG).show();
        }
    }

	@Override
	public void onConnectionInfoAvailable(WifiP2pInfo info) {
		// TODO Auto-generated method stub
		// 접속성공
		
		if (info.groupFormed && info.isGroupOwner) {
			Toast.makeText(this, "Server Init", Toast.LENGTH_LONG).show();
			new ServerAsyncTask(this.context, this).execute();
        } 
	}
	   
}

class LogFile {
	private static final long MIN_FILELENGTH = 1 * 1024 * 1024;	// 1 MB
	private String m_strLogFileFolderPath = "";
	private String m_strLogFileName = "filelog.txt";
	private long m_lLogFileLength = MIN_FILELENGTH;

	public LogFile(Context context) {
		if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
			m_strLogFileFolderPath = Environment.getExternalStorageDirectory().getAbsolutePath();
		}
		else {
			m_strLogFileFolderPath = "";
		}
	}

	public void setFileName(String strFileName) {
		if ((null != strFileName) && (0 < strFileName.length())) {
			m_strLogFileName = strFileName;
		}
	}
	
	public String getFileNameWithFullPath(){
		return m_strLogFileFolderPath + File.separator + m_strLogFileName;
	}

	public void setFileLength(long lFileLength) {
		if (MIN_FILELENGTH < lFileLength) {
			m_lLogFileLength = lFileLength;
		}
	}

	public void reset() {
		File file = new File(m_strLogFileFolderPath + "/" + m_strLogFileName);
		file.delete();

		write("LogFile.reset()");
	}

	public void write(String strMessage, Object ... args) {
		String _strMessage = strMessage;
		if ((strMessage == null) || (strMessage.length() == 0)) {
			return;
		}

		if (args.length != 0) {
			_strMessage = String.format(strMessage, args);
		}

		_strMessage = getCurrentTime() + " : " + _strMessage + "\n";

		File file = new File(m_strLogFileFolderPath + File.separator + m_strLogFileName);
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(file, true);
			if (fos != null) {
				fos.write(_strMessage.getBytes());
			}
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (fos != null) {
					fos.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}

	private static String getCurrentTime() {
		Calendar calendar = Calendar.getInstance();
		String strTime = String.format("%04d-%02d-%02d %02d:%02d:%02d.%03d",
				calendar.get(Calendar.YEAR), 
				calendar.get(Calendar.MONTH) + 1,
				calendar.get(Calendar.DAY_OF_MONTH),
				calendar.get(Calendar.HOUR_OF_DAY),
				calendar.get(Calendar.MINUTE),
				calendar.get(Calendar.SECOND),
				calendar.get(Calendar.MILLISECOND));

		return strTime;
	}
}

